/*
MIT License

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo/stars
*/

#ifndef SIMODO_module_ModuleManagement
#define SIMODO_module_ModuleManagement

/*! \file ModuleManagement.h
    \brief Управление модулями.
*/

#include "simodo/interpret/Interpret_interface.h"
#include "simodo/module/CodeSupplier_interface.h"
#include "simodo/interpret/ModuleManagement_interface.h"
#include "simodo/inout/token/InputStreamSupplier_interface.h"
#include "simodo/interpret/SemanticModuleFactory_interface.h"

#include "simodo/module/HardModuleLoader.h"
#include "simodo/inout/reporter/Reporter_abstract.h"
#include "simodo/loom/Loom.h"

#include <unordered_map>
#include <memory>

namespace simodo::module
{
    inline const std::string INITIAL_CONTRACTS_DIR  = "contracts";
    inline const std::string INITIAL_CONTRACTS_FILE = "initial-contracts.simodo-script";

    typedef std::shared_ptr<interpret::SemanticModuleFactory_interface> (InterpretFactory_t)(interpret::ModuleManagement_interface & module_management);

    class ModuleManagement : public interpret::ModuleManagement_interface
    {
        inout::Reporter_abstract &                  _m;                 ///< Обработчик сообщений
        std::vector<std::shared_ptr<interpret::SemanticModuleFactory_interface>>
                                                    _semantic_factories;
        inout::InputStreamSupplier_interface &      _stream_supplier;   ///< Система предоставления контента
        std::vector<std::string>                    _semantics_places;
        std::vector<std::string>                    _hard_module_places;
        std::vector<std::string>                    _grammar_places;
        interpret::InterpretType                    _interpret_type;
        interpret::SemanticDataCollector_interface &_semantic_data;
        std::ostream &                              _tout;
        std::string                                 _initial_contracts_file;
        bool                                        _debug_mode;
        uint64_t                                    _timeout;
        bool                                        _resume;
        bool                                        _need_full_debug_info;
        std::vector<interpret::BreakPoint>          _breakpoints;

        loom::Loom                                  _loom;              ///< Система исполнения SIMODO loom
        std::unique_ptr<CodeSupplier_interface>     _code_generator;    ///< Генерация кода с кешированием грамматик
        HardModuleLoader                            _hard_module_loader;

        std::unordered_map<std::string,std::shared_ptr<variable::Module_interface>>
                                                    _modules;
        inout::uri_set_t                            _files;

        std::string                                 _last_error;

        std::condition_variable                     _debug_condition;
        mutable std::mutex                          _debug_condition_mutex;
        
    public:
        ModuleManagement() = delete;
        ModuleManagement(inout::Reporter_abstract & m, 
                         inout::InputStreamSupplier_interface & stream_supplier,
                         std::vector<std::string> semantics_places,
                         std::vector<std::string> hard_module_places,
                         std::vector<std::string> grammar_places,
                         interpret::InterpretType interpret_type,
                         interpret::SemanticDataCollector_interface & semantic_data,
                         std::ostream & tout,
                         std::string initial_contracts_file,
                         bool debug_mode = false, 
                         uint64_t timeout = 0,
                         bool resume = false,
                         bool need_full_debug_info = false,
                         const std::vector<interpret::BreakPoint> & breakpoints = {}
                        );
    
        const inout::uri_set_t &    files() const { return _files; }

    public:
        virtual void                addSemanticFactories(std::vector<std::shared_ptr<interpret::SemanticModuleFactory_interface>> factories) override;
        virtual bool                execute(const std::string & module_name, std::vector<std::string> preload_module_names={}) override;

        virtual interpret::InterpretType     
                                    interpret_type()    const override { return _interpret_type; }
        virtual interpret::SemanticDataCollector_interface & 
                                    semantic_data()           override { return _semantic_data; }
        virtual std::ostream &      tout()                    override { return _tout; }

    protected:
        virtual bool                isTheModuleLoaded(const std::string & module_name) override;
        virtual const ast::Node *   getCode(const std::string & module_name, const inout::uri_set_t & files) override;
        virtual std::shared_ptr<variable::Module_interface>
                                    registerSoftModule(const std::string & module_name, std::shared_ptr<variable::Object> module) override;
        virtual std::shared_ptr<variable::Object>
                                    produceObject(const std::string & module_name,
                                            interpret::Interpret_interface * interpret = nullptr) override;
    
        virtual const std::string & last_error()        const override { return _last_error; }

    protected:
        void                        loadFactories();
        bool                        execute(interpret::Interpret_interface & inter, const std::string & file_name);
        bool                        debug(const inout::uri_set_t & files);

    private:
        void                        printFiberBranch(const std::vector<loom::FiberStructure> & fibers, 
                                                const loom::FiberStructure & fs, 
                                                const loom::Fiber_interface * causer,
                                                int depth = 0) const;                                              
        void                        printCallStack(const interpret::Interpret_interface & interp) const;  
        void                        printLocals(const interpret::Interpret_interface & causer, 
                                                interpret::boundary_index_t frame_index = 100000) const;
        std::string                 getInfo(const ast::Node * p) const;
        std::string                 getFiberName(const loom::FiberStructure & fs) const;
        const loom::FiberStructure &findFiberStructure(const std::vector<loom::FiberStructure> & fibers, const loom::Fiber_interface * p_fiber) const;
    };

}

#endif // SIMODO_module_ModuleManagement
